package com.briup.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.function.Function;

/**
 * @author Horry
 * @Description TODO
 * @date 2022-8-31-11:27
 */
public class JDBCUtil {
	//创建数据库连接池：获取数据库连接对象
	private static DataSource pool;//数据库连接资源

	static {
		//使用druid连接池
		Properties prop = new Properties();
		//使用类加载的方式读取文件
		InputStream in = JDBCUtil.class.getClassLoader()
				.getResourceAsStream("druid.properties");
		try {
			//将资源加载进prop对象中
			prop.load(in);
			pool = DruidDataSourceFactory.createDataSource(prop);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	//获取数据库连接对象
	public static Connection getConnection() {
		Connection conn = null;
		try {
			conn = pool.getConnection();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return conn;
	}

	//关闭DQL
	public static void close(Connection conn, Statement stat, ResultSet rs) {
		try {
			if (conn != null) {
				conn.close();
			}
			if (stat != null) {
				stat.close();
			}
			if (rs != null) {
				rs.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	//关闭DML
	public static void close(Connection conn, Statement stat) {
		close(conn, stat, null);
	}

	public static <T> T execute(String sql, Function<ResultSet, T> function) {
		Connection conn;
		Statement stat;
		ResultSet rs;
		try {
			conn = getConnection();
			stat = conn.createStatement();
			rs = stat.executeQuery(sql);
			//处理结果集
			return function.apply(rs);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	//封装执行DML语句操作
	public static void execute(String sql) {
		Connection conn;
		Statement stat;

		try {
			//获取数据库连接
			conn = getConnection();
			//获取statement对象
			stat = conn.createStatement();
			//执行sql语句
			boolean flag = stat.execute(sql);
			if (flag) {
				System.out.println("sql语句执行成功");
			} else {
				System.out.println("sql语句执行失败");
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	//进一步封装执行DQL语句的操作 反射：可以在运行期间创建对象，并且获取类的所有信息
	public static <T> List<T> execute(String sql, Class<T> tClass) {
		Connection conn;
		Statement stat;
		ResultSet rs;
		//创建list集合，用于装在实体类对象
		List<T> list = new ArrayList<>();
		try {
			conn = getConnection();
			stat = conn.createStatement();
			rs = stat.executeQuery(sql);
			//根据字节码对象查出相应类的属性
			Field[] fields = tClass.getDeclaredFields();
			//处理结果集
			while (rs.next()) {
				//创建相应的实体对象
				T t = tClass.newInstance();
				//对属性信息进行遍历操作，将数据注入进属性中
				for (Field field : fields) {
					String fieldName = field.getName();
					String fieldType = field.getType().getSimpleName();
					//属性值
					Object value = null;
					//如果属性的类型是string则进入以下操作
					if ("String".equals(fieldType)) {
						value = rs.getString(fieldName);
					}
					if ("int".equals(fieldType)) {
						value = rs.getInt(fieldName);
					}
					if ("double".equals(fieldType)) {
						value = rs.getDouble(fieldName);
					}
					if ("Date".equals(fieldType)) {
						value = rs.getDate(fieldType);
					}
					//将属性设置为可访问的，直接将属性注入进去 (不推荐)
					/*field.setAccessible(true);
					field.set(t, value);*/
					//通过构造器进行赋值 ，在封装时无法做到
					//通过set方法对属性进行赋值
					//拼接处相应的set方法
					String setMethodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
					//根据方法名及参数类型找到对应的set方法
					Method method = tClass.getDeclaredMethod(setMethodName, field.getType());
					//调用set方法给属性赋值
					method.invoke(t, value);
				}
				//将相应的对象放入list集合中
				list.add(t);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}
}
